/**
 *  @file SSLCallbacks.h
 */
#ifndef _SSLCALLBACKS_H_
#define _SSLCALLBACKS_H_

#include "../../common/BaseObject.h"
#include "../../text/CFString.h"

namespace cppflib
{

namespace security { namespace cert { class X509Certificate; } }

namespace net
{

namespace ssl
{

class SSLContext;

/**
 *  Callback interface to fetch password for the private key in a cert
 */
class _DLLAPI ISSLPrivateKeyPwdCallback : public BaseObject
{
public:
    ISSLPrivateKeyPwdCallback(void) { }
    virtual ~ISSLPrivateKeyPwdCallback(void) { }
    //! fill in 'pwd' with the password for private key
    virtual void GetPwd(CFString &pwd) = 0;
};

/**
 *  Callback interface to pass in the peer certificate chain during negotiation
 */
class _DLLAPI ISSLPeerCertCallback : public BaseObject
{
public:
    ISSLPeerCertCallback(void) { }
    virtual ~ISSLPeerCertCallback(void) { }
    /** 
     * This one is called during initial SSL negotiation/renegotiation. The whole cert chain from
     * peer is passed one by one with this method. Supposedly, there are 3 certs in a cert chain, this
     * method will be called 3 times (from root CA cert down to peer's own cert)
     *
     * Throw an exception derived from BaseException if don't want to accept the cert after examining it
     */
    virtual void ReadPeerCert(bool isCertOK, security::cert::X509Certificate &x509Cert) = 0;

    /**
     * This one is called after connection is established with peer. This will only be called once and
     * the cert passed in is the peer's own cert.
     *
     * Throw an exception derived from BaseException if don't want to accept the cert after examining it
     */
    virtual void ReadPeerCertAfterConnection(security::cert::X509Certificate &x509Cert) = 0;

    /**
     * For outside world to pass in the target host name so that derived class can check against during
     * ReadPeerCert or ReadPeerCertAfterConnection.
     *
     * This method is called when SSLSocket::SetAttribute() is called with the attribute 
     * Socket::SSL_TARGET_HOSTNAME.
     *
     * By default, it do nothing here.
     */
    virtual void SetTargetHostName(pcwstr_t hostName) { }
};

/**
 *  Callback interface to find matching SSLContext with matching hostname for a server socket
 *  (i.e. Server Name Indication -- SNI)
 */
class _DLLAPI ISSLFindMatchingHostNameCallback : public BaseObject
{
public:
    ISSLFindMatchingHostNameCallback(void) { }
    virtual ~ISSLFindMatchingHostNameCallback(void) { }

    /**
     * Find matching SSLContext with specified host name
     *
     * @return NULL if not found
     */
    virtual SSLContext *GetMatchingSSLContext(const CFString &hostName) = 0;
};

 
_DLLAPI bool IsHostNameMatched(const CFString & targetHostName, const CFString & hostNamePattern);

} // end of namespace ssl

} // end of namespace net

} // end of namespace cppflib

#endif
